package com.example.maxmin;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import sun.misc.Unsafe;

public class Main2 {
	static Unsafe U;

	static {
		try {
			var f = Unsafe.class.getDeclaredField("theUnsafe");
			f.setAccessible(true);
			U = (Unsafe)f.get(Unsafe.class);
		} catch (Exception e) {
			throw new Error(e);
		}
	}

	static class Point {
		public double x;
		public double y;
		public double z;
	}

	static double maxMin(long path1, int n1, long path2, int n2) {
		var max = 0.0;
		for (int j = 0; j < n1; j += 3) {
			var jx = U.getDouble(path1 + j * 8L);
			var jy = U.getDouble(path1 + j * 8L + 8);
			var jz = U.getDouble(path1 + j * 8L + 16);
			var min = Double.MAX_VALUE;
			int i = 0;
			for (; i < n2 - 9; i += 12) {
				var xd1 = U.getDouble(path2 + i * 8L) - jx;
				var yd1 = U.getDouble(path2 + i * 8L + 1 * 8L) - jy;
				var zd1 = U.getDouble(path2 + i * 8L + 2 * 8L) - jz;
				var xd2 = U.getDouble(path2 + i * 8L + 3 * 8L) - jx;
				var yd2 = U.getDouble(path2 + i * 8L + 4 * 8L) - jy;
				var zd2 = U.getDouble(path2 + i * 8L + 5 * 8L) - jz;
				var xd3 = U.getDouble(path2 + i * 8L + 6 * 8L) - jx;
				var yd3 = U.getDouble(path2 + i * 8L + 7 * 8L) - jy;
				var zd3 = U.getDouble(path2 + i * 8L + 8 * 8L) - jz;
				var xd4 = U.getDouble(path2 + i * 8L + 9 * 8L) - jx;
				var yd4 = U.getDouble(path2 + i * 8L + 10 * 8L) - jy;
				var zd4 = U.getDouble(path2 + i * 8L + 11 * 8L) - jz;
				var dist1 = Math.sqrt(xd1 * xd1 + yd1 * yd1 + zd1 * zd1);
				var dist2 = Math.sqrt(xd2 * xd2 + yd2 * yd2 + zd2 * zd2);
				var dist3 = Math.sqrt(xd3 * xd3 + yd3 * yd3 + zd3 * zd3);
				var dist4 = Math.sqrt(xd4 * xd4 + yd4 * yd4 + zd4 * zd4);
				if (min > dist1)
					min = dist1;
				if (min > dist2)
					min = dist2;
				if (min > dist3)
					min = dist3;
				if (min > dist4)
					min = dist4;
			}
			for (; i < n2; i += 3) {
				var xd = U.getDouble(path2 + i * 8L) - jx;
				var yd = U.getDouble(path2 + i * 8L + 8) - jy;
				var zd = U.getDouble(path2 + i * 8L + 16) - jz;
				var dist = Math.sqrt(xd * xd + yd * yd + zd * zd);
				if (min > dist)
					min = dist;
			}
			if (max < min)
				max = min;
		}
		return max;
	}

	static double hausdorffDistance(long path1, int n1, long path2, int n2) {
		return Math.max(maxMin(path1, n1, path2, n2), maxMin(path2, n2, path1, n1));
	}

	static long pointList2Array(ArrayList<Point> pVec) {
		var a = U.allocateMemory((long)pVec.size() * 3 * 8);
		int i = 0;
		for (var p : pVec) {
			U.putDouble(a + i, p.x);
			U.putDouble(a + i + 8, p.x);
			U.putDouble(a + i + 16, p.x);
			i += 24;
		}
		return a;
	}

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {
		var p1Json = Files.readString(Paths.get("../../path.json"));
		var p2Json = Files.readString(Paths.get("../../path1.json"));

		var listType = new TypeToken<ArrayList<Point>>() {
		}.getType();
		var p1Vec = (ArrayList<Point>)new Gson().fromJson(p1Json, listType);
		var p2Vec = (ArrayList<Point>)new Gson().fromJson(p2Json, listType);
		var p1Arr = pointList2Array(p1Vec);
		var p2Arr = pointList2Array(p2Vec);
		var n1 = p1Vec.size() * 3;
		var n2 = p2Vec.size() * 3;

		for (int i = 0; i < 3; i++)
			hausdorffDistance(p1Arr, n1, p2Arr, n2);

		var startTime = System.currentTimeMillis();
		var val = hausdorffDistance(p1Arr, n1, p2Arr, n2);
		System.out.printf("res is %f\n", val);
		System.out.printf("spend time is: %d ms\n", System.currentTimeMillis() - startTime);
	}
}
